# -*- coding:utf-8 -*-
# time: 2025/7/31 ♡  15:24
# author:张伟
import os.path
import time
from datetime import datetime, timedelta
from hashlib import md5
from flask import Blueprint, request, g, current_app, redirect, session, render_template
from flask_jwt_extended import jwt_required, get_jwt_identity, verify_jwt_in_request, create_access_token
from flask_jwt_extended.exceptions import NoAuthorizationError
from jwt import ExpiredSignatureError

from utils import restful
from .forms import UploadImageForm, AddBannerForm, EditBannnerForm, AddBoardForm, EditBoardForm, AddStaffForm, \
    EditStaffForm
from models.auth import UserModel, Permission, RoleModel
from models.post import BannerModel, PostModel, CommentModel, BoardModel
from exts import db, socketio
from sqlalchemy.sql import func
from .decorators import check_Permission, jwt_optional_with_user
from flask_socketio import join_room, leave_room

bp = Blueprint("cmsapi", __name__, url_prefix="/cmsapi")


@bp.before_request
@jwt_optional_with_user()
def before_request():
    if request.method == "OPTIONS":
        return

        # 特殊路由不需要token验证
    if request.endpoint in ['cmsapi.refresh_token']:
        return

    try:
        # 验证JWT token
        verify_jwt_in_request()
        identify = get_jwt_identity()
        user = UserModel.query.get(identify)
        if user:
            if not user.is_active:
                return restful.unlogin_error(message="账户已被禁用")
            else:
                setattr(g, "user", user)
        else:
            return restful.unlogin_error(message="用户不存在")
    except ExpiredSignatureError:
        # Token过期，返回特定错误码
        return restful.unlogin_error(message="Token已过期", data={"token_expired": True})
    except NoAuthorizationError:
        return restful.unlogin_error(message="未提供认证信息")
    except Exception as e:
        return restful.unlogin_error(message="认证失败")

@bp.post("/auth/refresh/")
@jwt_required(refresh=True)
def refresh_token():
    user_id = get_jwt_identity()
    # 生成新的Access token
    new_access_token = create_access_token(identity=user_id)
    return restful.ok(data={"access_token": new_access_token})


# 处理禁用用户事件
@socketio.on("join_user_room", namespace="/cmsapi")
def handle_join_user_room(data):
    # 数据验证
    if not data or not isinstance(data, dict):
        return
    token = data["token"]
    if token:
        request.headers = {'Authorization': f'Bearer {token}'}
        try:
            # 验证jwt token
            verify_jwt_in_request()
            current_user_id = get_jwt_identity()
            # 确保用户只能加入自己的房间
            user_id = data["user_id"]
            if str(current_user_id) == str(user_id):
                join_room(f"user_{user_id}")
        except Exception as e:
            socketio.emit("error", {"message": "身份验证异常！"}, room=request.sid, namespace="/cmaapi")
    else:
        try:
            user_id = data["user_id"]
            join_room(f"user_{user_id}")
        except Exception as e:
            socketio.emit("error", {"message": "身份验证异常！"}, room=request.sid, namespace="/cmaapi")


@socketio.on("leave_user_room", namespace="/")
def handle_leave_user_room(data):
    user_id = data["user_id"]
    leave_room(f"user_{user_id}")
    print(f"用户{user_id}离开用户{user_id}的房间")


@bp.get("/")
def index():
    identify = get_jwt_identity()
    return restful.ok(message="cms首页", data={"identify": identify})


@bp.get("/board/list/")
@check_Permission(Permission.BOARD)
def board_list():
    boards = BoardModel.query.order_by(BoardModel.create_time.desc()).all()
    board_dicts = [board.to_dict() for board in boards]
    return restful.ok(data=board_dicts)


@bp.post("/board/add/")
@check_Permission(Permission.BOARD)
def add_board():
    form = AddBoardForm(request.form)
    if form.validate():
        name = form.name.data
        priority = form.priority.data
        board = BoardModel(name=name, priority=priority)
        db.session.add(board)
        db.session.commit()
        return restful.ok(data=board.to_dict())
    else:
        return restful.params_error(message=form.messages[0])


@bp.post("/board/delete/")
@check_Permission(Permission.BOARD)
def delete_board():
    board_id = request.form.get("board_id")
    if not board_id:
        return restful.params_error(message="请传入板块ID！")
    board = BoardModel.query.get(board_id)
    if not board:
        return restful.params_error(message="板块不存在！")
    db.session.delete(board)
    db.session.commit()
    return restful.ok()


@bp.post("/board/edit/")
@check_Permission(Permission.BOARD)
def edit_board():
    form = EditBoardForm(request.form)
    if form.validate():
        id = form.id.data
        name = form.name.data
        priority = form.priority.data
        board = BoardModel.query.get(id)
        if not board:
            return restful.params_error(message="板块不存在！")
        board.name = name
        board.priority = priority
        db.session.commit()
        return restful.ok(data=board.to_dict())
    else:
        return restful.params_error(message=form.messages[0])


@bp.post("/banner/image/upload/")
@check_Permission(Permission.BANNER)
def banner_image_upload():
    form = UploadImageForm(request.files)
    if form.validate():
        image = form.image.data
        filename = image.filename
        _, ext = os.path.splitext(filename)
        filename = md5((g.user.email + str(time.time())).encode("utf-8")).hexdigest() + ext
        image_save_path = os.path.join(current_app.config["BANNER_IMAGE_SAVE_PATH"], filename)
        image.save(image_save_path)
        return restful.ok(data={"image_url": filename})
    else:
        message = form.messages[0]
        return restful.params_error(message=message)


@bp.post("/banner/add/")
@check_Permission(Permission.BANNER)
def add_banner():
    form = AddBannerForm(request.form)
    if form.validate():
        name = form.name.data
        image_url = form.image_url.data
        link_url = form.link_url.data
        priority = form.priority.data
        banner_model = BannerModel(name=name, image_url=image_url, link_url=link_url, priority=priority)
        db.session.add(banner_model)
        db.session.commit()
        return restful.ok(data=banner_model.to_dict())
    else:
        message = form.messages[0]
        return restful.params_error(message=message)


@bp.get("/banner/list/")
@check_Permission(Permission.BANNER)
def banner_list():
    banners = BannerModel.query.order_by(BannerModel.create_time.desc()).all()
    banner_dicts = [banner.to_dict() for banner in banners]
    return restful.ok(data=banner_dicts)


@bp.post("/banner/delete/")
@check_Permission(Permission.BANNER)
def delete_banner():
    banner_id = request.form.get("banner_id")
    if not banner_id:
        return restful.params_error(message="请传入轮播图ID！")
    banner = BannerModel.query.get(banner_id)
    if not banner:
        return restful.params_error(message="轮播图不存在！")
    db.session.delete(banner)
    db.session.commit()
    return restful.ok()


@bp.post("/banner/edit/")
@check_Permission(Permission.BANNER)
def edit_banner():
    form = EditBannnerForm(request.form)
    if form.validate():
        banner_id = form.id.data
        banner_model = BannerModel.query.get(banner_id)
        if not banner_model:
            return restful.params_error(message="轮播图不存在！")
        banner_model.name = form.name.data
        banner_model.image_url = form.image_url.data
        banner_model.link_url = form.link_url.data
        banner_model.priority = form.priority.data
        db.session.commit()
        return restful.ok(data=banner_model.to_dict())
    else:
        message = form.messages[0]
        return restful.params_error(message=message)


@bp.get("/post/list/")
@check_Permission(Permission.POST)
def post_list():
    page = request.args.get("page", type=int, default=1)
    page_size = current_app.config["PAGE_SIZE"]
    start = (page - 1) * page_size
    end = start + page_size
    query_obj = PostModel.query.order_by(PostModel.create_time.desc())
    page_count = query_obj.count()
    posts = query_obj.slice(start, end)
    post_dicts = [post.to_dict() for post in posts]
    return restful.ok(data={"page_count": page_count, "post_dicts": post_dicts, "page": page})


@bp.post("/post/delete/")
@check_Permission(Permission.POST)
def delete_post():
    post_id = request.form.get("post_id")
    if not post_id:
        return restful.params_error(message="请传入帖子ID！")
    post = PostModel.query.get(post_id)
    if not post:
        return restful.params_error(message="帖子不存在！")
    db.session.delete(post)
    db.session.commit()
    return restful.ok()


@bp.get("/comment/list/")
@check_Permission(Permission.COMMENT)
def comment_list():
    page = request.args.get("page", type=int, default=1)
    page_size = current_app.config["PAGE_SIZE"]
    start = (page - 1) * page_size
    end = start + page_size
    query_obj = CommentModel.query.order_by(CommentModel.create_time.desc())
    page_count = query_obj.count()
    comments = query_obj.slice(start, end)
    comment_dicts = [comment.to_dict() for comment in comments]
    return restful.ok(data={"page_count": page_count, "comment_dicts": comment_dicts, "page": page})


@bp.post("/comment/delete/")
@check_Permission(Permission.COMMENT)
def delete_comment():
    comment_id = request.form.get("comment_id")
    if not comment_id:
        return restful.params_error(message="请传入评论ID！")
    comment_model = CommentModel.query.get(comment_id)
    if not comment_model:
        return restful.params_error(message="评论不存在！")
    db.session.delete(comment_model)
    db.session.commit()
    return restful.ok()


@bp.get("/user/list/")
@check_Permission(Permission.USER)
def user_list():
    page = request.args.get("page", type=int, default=1)
    page_size = current_app.config["PAGE_SIZE"]
    start = (page - 1) * page_size
    end = start + page_size
    query_obj = UserModel.query.order_by(UserModel.join_time.desc()).filter_by(is_staff=False)
    page_count = query_obj.count()
    users = query_obj.slice(start, end)
    user_dicts = [user.to_dict() for user in users]
    return restful.ok(data={"page_count": page_count, "user_dicts": user_dicts, "page": page})


@bp.post("/user/is_active/")
@check_Permission(Permission.USER)
def user_is_active():
    user_id = request.form.get("user_id")
    is_active = request.form.get("is_active", type=int)
    if not user_id:
        return restful.params_error(message="请传入用户ID！")
    if is_active is None:
        return restful.params_error(message="请传入用户状态！")
    user = UserModel.query.get(user_id)
    if not user:
        return restful.params_error(message="用户不存在！")
    # 如果是禁用该用户，通过 WebSocket 通知该用户被禁用
    if is_active == 0 and user.is_active:
        try:
            socketio.emit("user_disabled", {
                "count_id": user_id,
                "message": "你的账号已被禁用，即将下线！"
            }, room=f"user_{user_id}", namespace="/cmsapi")
        except Exception as e:
            current_app.logger.error(f"WebSocket 通知失败: {e}")
    user.is_active = bool(is_active)
    db.session.commit()
    return restful.ok(data=user.to_dict())


@bp.get("/board/post/count/")
def board_post_count():
    board_post_count_list = db.session.query(BoardModel.name, func.count(PostModel.id)).outerjoin(PostModel).group_by(
        BoardModel.name).all()
    board_names = []
    post_nums = []
    for items in board_post_count_list:
        board_names.append(items[0])
        post_nums.append(items[1])
    return restful.ok(data={"board_names": board_names, "post_nums": post_nums})


@bp.get("/7day/post/count/")
def seven_day_post_count():
    now = datetime.now()
    seven_day_ago = now - timedelta(days=6, hours=now.hour, minutes=now.minute, seconds=now.second,
                                    microseconds=now.microsecond)
    seven_day_post_list = db.session.query(func.date_format(PostModel.create_time, "%Y-%m-%d"),
                                           func.count(PostModel.id)).group_by(
        func.date_format(PostModel.create_time, "%Y-%m-%d")).filter(PostModel.create_time >= seven_day_ago).all()
    seven_day_post_dicts = dict(seven_day_post_list)
    for i in range(7):
        date = seven_day_ago + timedelta(days=i)
        date_str = date.strftime("%Y-%m-%d")
        if date_str not in seven_day_post_dicts:
            seven_day_post_dicts[date_str] = 0
    dates = sorted(list(seven_day_post_dicts.keys()))
    post_nums = [seven_day_post_dicts[date] for date in dates]
    return restful.ok(data={"dates": dates, "post_nums": post_nums})


@bp.get("/staff/list/")
@check_Permission(Permission.STAFF)
def staff_list():
    page = request.args.get('page', type=int, default=1)
    page_size = current_app.config["PAGE_SIZE"]
    start = (page - 1) * page_size
    end = start + page_size
    query_obj = UserModel.query.filter_by(is_staff=True).order_by(UserModel.join_time.desc())
    staff_count = query_obj.count()
    staffs = query_obj.slice(start, end)
    staff_dicts = [staff.to_dict() for staff in staffs]
    roles = RoleModel.query.order_by(RoleModel.permissions).all()
    roles_dicts = [role.to_dict() for role in roles]
    return restful.ok(data={"page_count": staff_count, "staffs": staff_dicts, "page": page, "roles": roles_dicts})


@bp.post("/staff/active/")
@check_Permission(Permission.STAFF)
def active_staff():
    staff_id = request.form.get("staff_id")
    is_active = request.form.get("is_active", type=int)
    if not staff_id or is_active is None:
        return restful.params_error("请传入正确的参数")
    staff = UserModel.query.get(staff_id)
    if not staff:
        return restful.params_error("该员工不存在！")
    if is_active == 0 and staff.is_active:
        try:
            socketio.emit("user_disabled", {
                "count_id": staff_id,
                "message": "你的账号已被禁用，即将下线！"
            }, room=f"user_{staff_id}", namespace="/cmsapi")
        except Exception as e:
            current_app.logger.error(f"WebSocket 通知失败: {e}")
    staff.is_active = bool(is_active)
    db.session.commit()
    return restful.ok(data=staff.to_dict())


@bp.post("/staff/add/")
@check_Permission(Permission.STAFF)
def add_staff():
    form = AddStaffForm(request.form)
    if form.validate():
        name = form.name.data
        email = form.email.data
        role_id = form.role.data
        try:
            staff = UserModel(username=name, email=email, password="123456", is_staff=True, is_active=True,
                              role_id=role_id,
                              avatar="default_avatar.png")
            db.session.add(staff)
            db.session.commit()
            return restful.ok(data=staff.to_dict())
        except Exception as e:
            print(e)
            db.session.rollback()
            return restful.server_error()
    else:
        return restful.params_error(message=form.messages[0])


@bp.post("/staff/edit/")
@check_Permission(Permission.STAFF)
def edit_staff():
    form = EditStaffForm(request.form)
    if form.validate():
        staff_id = form.id.data
        name = form.name.data
        email = form.email.data
        role_id = form.role.data
        staff = UserModel.query.get(staff_id)
        if not staff:
            return restful.params_error(message="该员工不存在！")
        try:
            staff.name = name
            staff.email = email
            staff.role_id = role_id
            db.session.commit()
            return restful.ok(data=staff.to_dict())
        except Exception as e:
            print(e)
            return restful.server_error()
    else:
        return restful.params_error(message=form.messages[0])


@bp.post("/staff/delete/")
@check_Permission(Permission.STAFF)
def delete_staff():
    staff_id = request.form.get("staff_id")
    if not staff_id:
        return restful.params_error(message="请传入员工ID！")
    staff = UserModel.query.get(staff_id)
    if not staff:
        return restful.params_error(message="该员工不存在！")
    try:
        db.session.delete(staff)
        db.session.commit()
        return restful.ok()
    except Exception as e:
        print(e)
        return restful.server_error()
